﻿using System;
using System.Diagnostics;
using System.Net;
using Model.Nova;
using Network;
using Network.Messages.LiveControl;
using Network.Messages.Nova;
using Providers.Nova.Modules;

namespace Providers.Nova.Server
{
    public class NovaProvider : Provider
    {
        private static readonly object SyncLock = new object();
        private static bool _alreadySent;

        private static readonly object SyncLock2 = new object();
        private static bool _alreadySent2;


        public IPEndPoint Client;

        public NovaProvider(NetworkPeer network)
            : base(network)
        {
            ServerMachine = new Machine();
        }

        /// <summary>
        ///     Represents the current server's machine, used to store the current session password.
        /// </summary>
        public Machine ServerMachine { get; set; }

        public override void RegisterMessageHandlers()
        {
            Network.RegisterUnconnectedMessageHandler<ResponseIntroducerRegistrationDeniedMessage>(
                OnResponseIntroducerRegistrationDeniedMessageReceived);
            Network.RegisterUnconnectedMessageHandler<ResponseIntroducerRegistrationSucceededMessage>(
                OnResponseIntroducerRegistrationSucceededMessageReceived);
            Network.OnConnected += Network_OnConnected;
            Network.OnNatTraversalSucceeded += Network_OnNatTraversalSucceeded;

            Network.RegisterUnconnectedMessageHandler<RequestSelfMachineInfoMessage>(
                OnRequestSelfMachineInfoMessageReceived);

            Network.RegisterUnconnectedMessageHandler<RequestSelfMachineNewPassword>(
                OnRequestSelfMachineNewPasswordMessageReceived);

            Network.RegisterUnconnectedMessageHandler<ResponseKeepAliveMessage>(OnResponseAliveMessageReceived);

            Network.RegisterUnconnectedMessageHandler<AskServerShutdownMessage>(OnAskServerShutdownMessageRecived);
        }

        private void OnAskServerShutdownMessageRecived(UnconnectedMessageEventArgs<AskServerShutdownMessage> obj)
        {
            OnAskServerShutdownMessage?.Invoke(this,obj.Message);
        }

        private void OnResponseAliveMessageReceived(UnconnectedMessageEventArgs<ResponseKeepAliveMessage> obj)
        {
            if (obj.Message.FlagConnectionLosted)
            {
                OnConnectionLosted?.Invoke(this, new EventArgs());
            }
           
        }

        private void OnRequestSelfMachineNewPasswordMessageReceived(
            UnconnectedMessageEventArgs<RequestSelfMachineNewPassword> e)
        {
            var hardwareId = e.Message.Identity;
            if (hardwareId != ServerMachine.Identity)
            {
                //todo 发送失败消息，设备ID不对，不允许对外发送密码信息。
            }
            else
            {
                OnRequestNewPassword?.Invoke(this,new EventArgs());
                 Client = e.From;
            }
        }

        private void OnRequestSelfMachineInfoMessageReceived(
            UnconnectedMessageEventArgs<RequestSelfMachineInfoMessage> e)
        {
            var hardwareId = e.Message.Identity;
            if (hardwareId != ServerMachine.Identity)
            {
                //todo 发送失败消息，设备ID不对，不允许对外发送密码信息。
            }
            else
            {
                Client = e.From;
                NotifyClientUserInfoChanged();
            }
        }

        private void Network_OnNatTraversalSucceeded(object sender, NatTraversedEventArgs e)
        {
            Trace.WriteLine("Server:  Network_OnNatTraversalSucceeded()");

            lock (SyncLock)
            {
                if (!_alreadySent || true)
                {
                    _alreadySent = true;

                    Trace.WriteLine("Server:  Network_OnNatTraversalSucceeded()  [Final Time]");

                    _alreadySent = true;
                    try
                    {
                        Network.Connect(e.From);
                    }
                    catch (Exception)
                    {
                        // ignored
                    }
                }
            }
        }

        private void OnResponseIntroducerRegistrationDeniedMessageReceived(
            UnconnectedMessageEventArgs<ResponseIntroducerRegistrationDeniedMessage> e)
        {
            OnIntroducerRegistrationResponded?.Invoke(this,
                new IntroducerRegistrationResponsedEventArgs
                {
                    RegistrationResult = IntroducerRegistrationResponsedEventArgs.Result.Denied
                });
        }

        private void OnResponseIntroducerRegistrationSucceededMessageReceived(
            UnconnectedMessageEventArgs<ResponseIntroducerRegistrationSucceededMessage> e)
        {
            OnIntroducerRegistrationResponded?.Invoke(this,
                new IntroducerRegistrationResponsedEventArgs
                {
                    RegistrationResult = IntroducerRegistrationResponsedEventArgs.Result.Succeeded,
                    NovaId = e.Message.Machine.NovaId
                });

            ServerMachine.NovaId = e.Message.Machine.NovaId;

            NotifyClientUserInfoChanged();

            // Client will request NAT introduction, which leads to Server_OnNatTraversalSuccess() in the Client code block
        }

        public void NotifyClientUserInfoChanged()
        {
            if (Client == null || ServerMachine.NovaId == null || ServerMachine.Password == null)
            {
                return;
            }
            //通知客户端账户密码发生了修改
            var novaId = ServerMachine.NovaId;
            var password = ServerMachine.Password;

            var tMessage = new ResponseSelfMachineInfoMessage
            {
                NovaId = novaId,
                Password = password
            };
            Network.SendUnconnectedMessage(tMessage, Client);
        }

        // Warning - this event can be called multiple times
        private void Network_OnConnected(object sender, ConnectedEventArgs e)
        {
            Trace.WriteLine("Server:  Network_OnConnected()");

            lock (SyncLock2)
            {
                if (!_alreadySent2 || true)
                {
                    _alreadySent2 = true;

                    Trace.WriteLine("Server:  Network_OnConnected()  [Final Time]");
                }
            }
        }

        public event EventHandler<IntroducerRegistrationResponsedEventArgs> OnIntroducerRegistrationResponded;
        public event EventHandler<EventArgs> OnRequestNewPassword;
        public event EventHandler<EventArgs> OnConnectionLosted;
        public event EventHandler<AskServerShutdownMessage> OnAskServerShutdownMessage;



    }
}